home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / triq / 4d / math.asm < prev    next >
Encoding:
Assembly Source File  |  1992-09-12  |  48.1 KB  |  1,874 lines

  1.         page    ,132
  2. ;---------------------------Module-Header-------------------------------;
  3. ; Module Name: MATH.ASM
  4. ;
  5. ; Contains FIXED point math routines.
  6. ;
  7. ; Copyright (c) 1987  Microsoft Corporation
  8. ;-----------------------------------------------------------------------;
  9.  
  10. ;     (C) Copyright Microsoft Corp. 1987,1991.  All rights reserved.
  11. ;
  12. ;     You have a royalty-free right to use, modify, reproduce and 
  13. ;     distribute the Sample Files (and/or any modified version) in 
  14. ;     any way you find useful, provided that you agree that 
  15. ;     Microsoft has no warranty obligations or liability for any 
  16. ;     Sample Application Files which are modified. 
  17.  
  18. ?WIN    = 0
  19. ?PLM    = 1
  20. ?NODATA = 0
  21. ?386    = 1
  22.  
  23.     .286
  24.         .xlist
  25.         include cmacros.inc
  26.         .list
  27.  
  28. UQUAD   struc
  29. uq0     dw      ?
  30. uq1     dw      ?
  31. uq2     dw      ?
  32. uq3     dw      ?
  33. UQUAD    ends
  34.  
  35. PTL    struc
  36. ptl_x    dd    ?
  37. ptl_y    dd    ?
  38. PTL    ends
  39.  
  40. POINTFX struc
  41. x       dd      ?
  42. y       dd      ?
  43. z       dd      ?
  44. w       dd      ?
  45. POINTFX ends
  46.  
  47.  
  48. MAXINT equ 7FFFh
  49. MININT equ 8000h
  50.  
  51.  
  52. ;       The following two equates are just used as shorthand
  53. ;       for the "word ptr" and "byte ptr" overrides.
  54.  
  55. wptr    equ     word ptr
  56. bptr    equ     byte ptr
  57.  
  58. ; The following structure should be used to access high and low
  59. ; words of a DWORD.  This means that "word ptr foo[2]" -> "foo.hi".
  60.  
  61. LONG    struc
  62. lo      dw      ?
  63. hi      dw      ?
  64. LONG    ends
  65.  
  66. FARPOINTER      struc
  67. off     dw      ?
  68. sel     dw      ?
  69. FARPOINTER      ends
  70.  
  71. assert macro   a,b,c,d
  72. endm
  73.  
  74. EAXtoDXAX   macro
  75.         shld    edx,eax,16      ; move HIWORD(eax) to dx
  76.         endm
  77.  
  78. DXAXtoEAX   macro
  79.         ror     eax,16          ; xchg HIWORD(eax) and LOWORD(eax)
  80.         shrd    eax,edx,16      ; move LOWORD(edx) to HIWORD(eax)
  81.         endm
  82.  
  83. createSeg MATH_TEXT,MathSeg,word,public,CODE
  84. createSeg TRIG_TEXT,TrigSeg,word,public,CODE
  85.  
  86. ;---------------------------Public-Routine------------------------------;
  87. ; multiply                                                              ;
  88. ;                                                                       ;
  89. ; Multiplies two 32 bit fixed point numbers.  FIXED is a signed 32 bit  ;
  90. ; number with 16 bits of integer and 16 bits of fraction.               ;
  91. ;                                                                       ;
  92. ; This routine is pretty small and very popular.  We therefore put a    ;
  93. ; copy in each of several segments.                                     ;
  94. ;                                                                       ;
  95. ; Entry:                                                                ;
  96. ;       DX:AX = FIXED x                                                 ;
  97. ;       CX:BX = FIXED y                                                 ;
  98. ; Returns:                                                              ;
  99. ;       OF = 0                                                          ;
  100. ;         DX:AX = FIXED x*y                                             ;
  101. ;         BX    = error term                                            ;
  102. ; Error Returns:                                                        ;
  103. ;       OF = 1                                                          ;
  104. ; Registers destroyed:                                                  ;
  105. ;       BX,CX                                                           ;
  106. ;-----------------------------------------------------------------------;
  107. ; Breaks the 32 bit multiply into four 16 bit multiplies.  The key      ;
  108. ; feature of this routine is the way that the 32 bit numbers are        ;
  109. ; "SPLIT".  This means that we break up the 32 bit signed numbers into  ;
  110. ; two 16 bit signed numbers.  After the breakup, the upper word,        ;
  111. ; say X.1, is assumed to be the upper word of a 32 bit signed integer   ;
  112. ; whose lower word is 0000.  The lower word is assumed to be the lower  ;
  113. ; 16 bits of a 32 bit signed word, THE UPPER WORD OF WHICH CAN BE       ;
  114. ; GENERATED AS A SIGN EXTENSION OF THE LOWER WORD.  As an example,      ;
  115. ; consider what we do with the number 2.500:                            ;
  116. ;                                                                       ;
  117. ;     In FIXED notation:   2.500 = 00028000h                            ;
  118. ;                                                                       ;
  119. ;     We break it up as:         = 00030000h + FFFF8000h = 3.000 - .500 ;
  120. ;                                                                       ;
  121. ;     So, in SPLIT notation:     = 00038000h                            ;
  122. ;                                                                       ;
  123. ; This allows the upper and lower words to each be treated as a signed  ;
  124. ; 16 bit integer in their own right.  Thus, we can use the signed       ;
  125. ; multiply instruction IMUL.                                            ;
  126. ;-----------------------------------------------------------------------;
  127.  
  128. multiply_fixed  macro
  129.         local   multiply_fixed_done
  130.  
  131. ; make arg1 a SPLIT
  132.  
  133.         mov     di,dx
  134.         cwd
  135.         sub     di,dx
  136.         mov     si,ax                   ; SPLIT arg1 in DI:SI
  137.  
  138. ; make arg2 a SPLIT
  139.  
  140.         mov     ax,bx
  141.         cwd
  142.         sub     cx,dx                   ; SPLIT arg2 in CX:BX
  143.  
  144.                                         ;  AX  BX  CX  DX  SI  DI
  145.                                         ;  --  y.0 y.1 --  x.0 x.1
  146.  
  147. ; start multiplying the high order words, this saves a register
  148.  
  149.         mov     ax,cx                   ;  Y.1 y.0 Y.1 --  x.0 X.1
  150.  
  151. ; X.1 * Y.1
  152.  
  153.         imul    di                      ;  p.1 y.0 Y.1 --  x.0 X.1
  154.         jo      multiply_fixed_done
  155.         xchg    ax,cx                   ;  Y.1 y.0 p.1 --  x.0 X.1
  156.  
  157. ; x.0 * Y.1
  158.  
  159.         imul    si                      ;  p.0 y.0 p.1 p.1 x.0 X.1
  160.         add     cx,dx                   ;  p.0 y.0 p.1 --  x.0 X.1
  161.         jo      multiply_fixed_done
  162.         xchg    ax,di                   ;  X.1 y.0 p.1 --  x.0 p.0
  163.  
  164. ; X.1 * y.0
  165.  
  166.         imul    bx                      ;  p.0 y.0 p.1 p.1 x.0 p.0
  167.         add     di,ax                   ;  --  y.0 p.1 p.1 x.0 p.0
  168.         adc     cx,dx                   ;  --  y.0 p.1 --  x.0 p.0
  169.         jo      multiply_fixed_done
  170.         xchg    ax,bx                   ;  y.0 --  p.1 --  x.0 p.0
  171.  
  172. ; x.0 * y.0
  173.  
  174.         imul    si                      ;  p.e --  p.1 p.0 x.0 p.0
  175.         xchg    ax,bx                   ;  --  p.e p.1 p.0 --  p.0
  176.         xchg    ax,dx                   ;  p.0 p.e p.1 --  --  p.0
  177.         cwd                             ;  p.0 p.e p.1 cwd --  p.0
  178.         add     ax,di                   ;  p.0 p.e p.1 cwd --  -- 
  179.         adc     dx,cx                   ;  p.0 p.e --  p.1 --  -- 
  180. multiply_fixed_done:
  181.         endm
  182.  
  183. sBegin    MathSeg
  184.     assumes cs,MathSeg
  185.     assumes ds,nothing
  186.     assumes es,nothing
  187.  
  188. if ?386
  189.     .386
  190. endif
  191.  
  192. if ?386
  193.     cProc   multiply,<FAR,PUBLIC>
  194.         ParmD  fx1
  195.         ParmD  fx2
  196.     cBegin
  197.         mov     eax,fx1
  198.         imul    fx2     ; result is in    LOWORD(edx):HIWORD(eax)
  199.         shr     eax,16
  200.     cEnd
  201. else
  202.     cProc   multiply,<FAR,PUBLIC>,<si,di>
  203.         ParmD  fx1
  204.         ParmD  fx2
  205.     cBegin
  206.         mov     ax,fx1.lo
  207.         mov     dx,fx1.hi
  208.  
  209.         mov     bx,fx2.lo
  210.         mov     cx,fx2.hi
  211.  
  212.         call    idmul        ; dx:cx:bx:ax = dx:ax * cx:bx
  213.  
  214.         mov     dx,cx        ; dx:ax = dx:cx:bx:ax >> 16
  215.         mov     ax,bx
  216.     ;;          multiply_fixed
  217.     cEnd
  218. endif
  219.  
  220. ;------------------------------    Public   -------------------------------;
  221. ; fxRound
  222. ;
  223. ; Return the fixed number corresponding to the rounding of the input
  224. ; fixed number.
  225. ;
  226. ; Entry:
  227. ;       Rhi,Rlo: registers containing the .hi and .lo portions
  228. ;                of the fixed number.
  229. ; Returns:
  230. ;       Rhi,Rlo:        The answer is returned the the same registers
  231. ; Error Returns:
  232. ;       none
  233. ;
  234. ;--------------------------------------------------------------------------;
  235. cProc fxRound, <FAR, PASCAL>
  236.     ParmD  fx
  237. cBegin
  238.     mov    ax,fx.lo
  239.     mov    dx,fx.hi
  240.  
  241.     add    ax,ax
  242.     adc    dx,0
  243.     xor    ax,ax
  244. cEnd
  245.  
  246. ;---------------------------Public-Routine------------------------------;
  247. ; ulNormalize
  248. ;
  249. ; Normalizes a ULONG so that the highest order bit is 1.  Returns the
  250. ; number of shifts done.  Also returns ZF=1 if the ULONG was zero.
  251. ;
  252. ; Entry:
  253. ;       DX:AX = ULONG
  254. ; Returns:
  255. ;       DX:AX = normalized ULONG
  256. ;       CX    = shift count
  257. ;       ZF    = 1 if the ULONG is zero, 0 otherwise
  258. ; Registers Destroyed:
  259. ;       none
  260. ;-----------------------------------------------------------------------;
  261.  
  262.         assumes ds,nothing
  263.         assumes es,nothing
  264.  
  265. cProc   ulNormalize,<PUBLIC,NEAR>
  266. cBegin
  267.  
  268. ; shift by words
  269.  
  270.         xor     cx,cx
  271.         or      dx,dx
  272.         js      ulNormalize_exit
  273.         jnz     top_word_ok
  274.         xchg    ax,dx
  275.         or      dx,dx
  276.         jz      ulNormalize_exit        ; the zero exit
  277.         mov     cl,16
  278.         js      ulNormalize_exit
  279. top_word_ok:
  280.  
  281. ; shift by bytes
  282.  
  283.         or      dh,dh
  284.         jnz     top_byte_ok
  285.         xchg    dh,dl
  286.         xchg    dl,ah
  287.         xchg    ah,al
  288.         add     cl,8
  289.         or      dh,dh
  290.         js      ulNormalize_exit
  291. top_byte_ok:
  292.  
  293. ; do the rest by bits
  294.  
  295.         inc     cx
  296.         add     ax,ax
  297.         adc     dx,dx
  298.         js      ulNormalize_exit
  299.         inc     cx
  300.         add     ax,ax
  301.         adc     dx,dx
  302.         js      ulNormalize_exit
  303.         inc     cx
  304.         add     ax,ax
  305.         adc     dx,dx
  306.         js      ulNormalize_exit
  307.         inc     cx
  308.         add     ax,ax
  309.         adc     dx,dx
  310.         js      ulNormalize_exit
  311.         inc     cx
  312.         add     ax,ax
  313.         adc     dx,dx
  314.         js      ulNormalize_exit
  315.         inc     cx
  316.         add     ax,ax
  317.         adc     dx,dx
  318.         js      ulNormalize_exit
  319.         inc     cx
  320.         add     ax,ax
  321.         adc     dx,dx
  322. ulNormalize_exit:
  323. cEnd
  324.  
  325. ;---------------------------Public-Routine------------------------------;
  326. ; far_idmul
  327. ;       see idmul below.
  328. ;-----------------------------------------------------------------------;
  329.  
  330.         assumes ds,nothing
  331.         assumes es,nothing
  332.  
  333. cProc   far_idmul,<PUBLIC,FAR,NONWIN,NODATA>
  334. cBegin
  335.         cCall   idmul
  336.  
  337. cEnd
  338.  
  339. ;---------------------------Public-Routine------------------------------;
  340. ; idmul
  341. ;
  342. ; This is an extended precision multiply routine, intended to emulate
  343. ; 80386 imul instruction.
  344. ;
  345. ; Entry:
  346. ;       DX:AX = LONG
  347. ;       CX:BX = LONG
  348. ; Returns:
  349. ;       DX:CX:BX:AX = QUAD product
  350. ; Registers Destroyed:
  351. ;       none
  352. ;-----------------------------------------------------------------------;
  353.  
  354.         assumes ds,nothing
  355.         assumes es,nothing
  356.  
  357. cProc   idmul,<PUBLIC,NEAR>,<si,di>
  358.         localQ  qTemp
  359. cBegin
  360.  
  361. ; put one argument in safe registers
  362.  
  363.         mov     si,dx
  364.         mov     di,ax
  365.  
  366. ; do the low order unsigned product
  367.  
  368.         mul     bx
  369.         mov     qTemp.uq0,ax
  370.         mov     qTemp.uq1,dx
  371.  
  372. ; do the high order signed product
  373.  
  374.         mov     ax,si
  375.         imul    cx
  376.         mov     qTemp.uq2,ax
  377.         mov     qTemp.uq3,dx
  378.  
  379. ; do a mixed product
  380.  
  381.         mov     ax,si
  382.         cwd
  383.         and     dx,bx
  384.         sub     qTemp.uq2,dx            ; adjust for sign bit
  385.         sbb     qTemp.uq3,0
  386.         mul     bx
  387.         add     qTemp.uq1,ax
  388.         adc     qTemp.uq2,dx
  389.         adc     qTemp.uq3,0
  390.  
  391. ; do the other mixed product
  392.  
  393.         mov     ax,cx
  394.         cwd
  395.     and    dx,di
  396.         sub     qTemp.uq2,dx
  397.         sbb     qTemp.uq3,0
  398.         mul     di
  399.  
  400. ; pick up the answer
  401.  
  402.         mov     bx,ax
  403.         mov     cx,dx
  404.         xor     dx,dx
  405.  
  406.         mov     ax,qTemp.uq0
  407.         add     bx,qTemp.uq1
  408.         adc     cx,qTemp.uq2
  409.         adc     dx,qTemp.uq3
  410. cEnd
  411.  
  412. ;---------------------------Public-Routine------------------------------;
  413. ; far_dmul
  414. ;       see dmul below.
  415. ;-----------------------------------------------------------------------;
  416.  
  417.         assumes ds,nothing
  418.         assumes es,nothing
  419.  
  420. cProc   far_dmul,<PUBLIC,FAR,NONWIN,NODATA>
  421. cBegin
  422.         cCall   dmul
  423. cEnd
  424.  
  425. ;---------------------------Public-Routine------------------------------;
  426. ; dmul
  427. ;
  428. ; This is an extended precision multiply routine, intended to emulate
  429. ; 80386 mul instruction.
  430. ;
  431. ; Entry:
  432. ;       DX:AX = LONG
  433. ;       CX:BX = LONG
  434. ; Returns:
  435. ;       DX:CX:BX:AX = QUAD product
  436. ; Registers Destroyed:
  437. ;       none
  438. ;-----------------------------------------------------------------------;
  439.  
  440.         assumes ds,nothing
  441.         assumes es,nothing
  442.  
  443. cProc   dmul,<PUBLIC,NEAR>,<si,di>
  444.         localQ  qTemp
  445. cBegin
  446.  
  447. ; put one argument in safe registers
  448.  
  449.         mov     si,dx
  450.         mov     di,ax
  451.  
  452. ; do the low order product
  453.  
  454.         mul     bx
  455.         mov     qTemp.uq0,ax
  456.         mov     qTemp.uq1,dx
  457.  
  458. ; do the high order product
  459.  
  460.         mov     ax,si
  461.         mul     cx
  462.         mov     qTemp.uq2,ax
  463.         mov     qTemp.uq3,dx
  464.  
  465. ; do a mixed product
  466.  
  467.         mov     ax,si
  468.         mul     bx
  469.         add     qTemp.uq1,ax
  470.         adc     qTemp.uq2,dx
  471.         adc     qTemp.uq3,0
  472.  
  473. ; do the other mixed product
  474.  
  475.         mov     ax,cx
  476.         mul     di
  477.  
  478. ; pick up the answer
  479.  
  480.         mov     bx,ax
  481.         mov     cx,dx
  482.         xor     dx,dx
  483.         mov     ax,qTemp.uq0
  484.         add     bx,qTemp.uq1
  485.         adc     cx,qTemp.uq2
  486.         adc     dx,qTemp.uq3
  487. cEnd
  488.  
  489. ;---------------------------Public-Routine------------------------------;
  490. ; far_iqdiv
  491. ;       see iqdiv below.
  492. ;-----------------------------------------------------------------------;
  493.  
  494.         assumes ds,nothing
  495.         assumes es,nothing
  496.  
  497. cProc   far_iqdiv,<PUBLIC,FAR,NONWIN,NODATA>
  498. cBegin
  499.         cCall   iqdiv
  500. cEnd
  501.  
  502. ;---------------------------Public-Routine------------------------------;
  503. ; iqdiv
  504. ;
  505. ; This is an extended precision divide routine which is intended to
  506. ; emulate the 80386 64 bit/32 bit IDIV instruction.  We don't have the
  507. ; 32 bit registers to work with, but we pack the arguments and results
  508. ; into what registers we do have.  We will divide two signed numbers
  509. ; and return the quotient and remainder.  We will do INT 0 for overflow,
  510. ; just like the 80386 microcode.  This should ease conversion later.
  511. ;
  512. ; This routine just keeps track of the signs and calls qdiv to do the
  513. ; real work.
  514. ;
  515. ; Entry:
  516. ;       DX:CX:BX:AX = QUAD Numerator
  517. ;       SI:DI       = LONG Denominator
  518. ; Returns:
  519. ;       DX:AX = quotient
  520. ;       CX:BX = remainder
  521. ; Registers Destroyed:
  522. ;       DI,SI
  523. ; Wrote it.
  524. ;-----------------------------------------------------------------------;
  525.  
  526. WIMP    equ     1
  527.  
  528. IQDIV_RESULT_SIGN       equ     1
  529. IQDIV_REM_SIGN          equ     2
  530.  
  531.         assumes ds,nothing
  532.         assumes es,nothing
  533.  
  534. cProc   iqdiv,<PUBLIC,NEAR>
  535.         localB  flags
  536. cBegin
  537.         mov     flags,0
  538.  
  539. ; take the absolute value of the denominator
  540.  
  541.         or      si,si
  542.         jns     denominator_is_cool
  543.         xor     flags,IQDIV_RESULT_SIGN
  544.         neg     di
  545.         adc     si,0
  546.         neg     si
  547. denominator_is_cool:
  548.  
  549. ; take the absolute value of the denominator
  550.  
  551.         or      dx,dx
  552.         jns     numerator_is_cool
  553.         xor     flags,IQDIV_RESULT_SIGN + IQDIV_REM_SIGN
  554.         not     ax
  555.         not     bx
  556.         not     cx
  557.         not     dx
  558.         add     ax,1
  559.         adc     bx,0
  560.         adc     cx,0
  561.         adc     dx,0
  562. numerator_is_cool:
  563.  
  564. ; do the unsigned division
  565.  
  566.         call    qdiv
  567. ifdef WIMP
  568.         jo      iqdiv_exit
  569. endif
  570.  
  571. ; check for overflow
  572.  
  573.         or      dx,dx
  574.         jns     have_a_bit_to_spare
  575. ifdef WIMP
  576.         mov     ax,8000h
  577.         dec     ah
  578.         jmp     short iqdiv_exit
  579. else
  580.         int     0                       ; You're toast, Jack!
  581. endif
  582. have_a_bit_to_spare:
  583.  
  584. ; negate the result, if required
  585.  
  586.         test    flags,IQDIV_RESULT_SIGN
  587.         jz      result_is_done
  588.         neg     ax
  589.         adc     dx,0
  590.         neg     dx
  591. result_is_done:
  592.  
  593. ; negate the remainder, if required
  594.  
  595.         test    flags,IQDIV_REM_SIGN
  596.         jz      remainder_is_done
  597.         neg     bx
  598.         adc     cx,0
  599.         neg     cx
  600. remainder_is_done:
  601. iqdiv_exit:
  602. cEnd
  603.  
  604. ;---------------------------Public-Routine------------------------------;
  605. ; far_qdiv
  606. ;       see qdiv below.
  607. ;-----------------------------------------------------------------------;
  608.  
  609.         assumes ds,nothing
  610.         assumes es,nothing
  611.  
  612. cProc   far_qdiv,<PUBLIC,FAR,NONWIN,NODATA>
  613. cBegin
  614.         cCall   qdiv
  615. cEnd
  616.  
  617. ;---------------------------Public-Routine------------------------------;
  618. ; qdiv
  619. ;
  620. ; This is an extended precision divide routine which is intended to
  621. ; emulate the 80386 64 bit/32 bit DIV instruction.  We don't have the
  622. ; 32 bit registers to work with, but we pack the arguments and results
  623. ; into what registers we do have.  We will divide two unsigned numbers
  624. ; and return the quotient and remainder.  We will do INT 0 for overflow,
  625. ; just like the 80386 microcode.  This should ease conversion later.
  626. ;
  627. ; Entry:
  628. ;       DX:CX:BX:AX = UQUAD Numerator
  629. ;       SI:DI       = ULONG Denominator
  630. ; Returns:
  631. ;       DX:AX = quotient
  632. ;       CX:BX = remainder
  633. ; Registers Destroyed:
  634. ;       none
  635. ;-----------------------------------------------------------------------;
  636.  
  637.         assumes ds,nothing
  638.         assumes es,nothing
  639.  
  640. cProc   qdiv,<PUBLIC,NEAR>,<si,di>
  641.         localQ  uqNumerator
  642.         localD  ulDenominator
  643.         localD  ulQuotient
  644.         localW  cShift
  645. cBegin
  646.  
  647. ; stuff the quad word into local memory
  648.  
  649.         mov     uqNumerator.uq0,ax
  650.         mov     uqNumerator.uq1,bx
  651.         mov     uqNumerator.uq2,cx
  652.         mov     uqNumerator.uq3,dx
  653.  
  654.  
  655. ; check for overflow
  656.  
  657. qdiv_restart:
  658.         cmp     si,dx
  659.         ja      qdiv_no_overflow
  660.         jb      qdiv_overflow
  661.         cmp     di,cx
  662.         ja      qdiv_no_overflow
  663. qdiv_overflow:
  664. ifdef WIMP
  665.         mov     ax,8000h
  666.         dec     ah
  667.         jmp     qdiv_exit
  668. else
  669.         int     0                       ; You're toast, Jack!
  670.         jmp     qdiv_restart
  671. endif
  672. qdiv_no_overflow:
  673.  
  674. ; check for a zero Numerator
  675.  
  676.         or      ax,bx
  677.         or      ax,cx
  678.         or      ax,dx
  679.         jz      qdiv_exit_relay         ; quotient = remainder = 0
  680.  
  681. ; handle the special case when the denominator lives in the low word
  682.  
  683.         or      si,si
  684.         jnz     not_that_special
  685.  
  686. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=0):DI
  687.  
  688.         cmp     di,1                    ; separate out the trivial case
  689.         jz      div_by_one
  690.         xchg    dx,cx                   ; CX = remainder.hi = 0
  691.         mov     ax,bx
  692.         div     di
  693.         mov     bx,ax                   ; BX = quotient.hi
  694.         mov     ax,uqNumerator.uq0
  695.         div     di                      ; AX = quotient.lo
  696.         xchg    bx,dx                   ; DX = quotient.hi, BX = remainder.lo
  697. ifdef WIMP
  698.         or      ax,ax           ; clear OF
  699. endif
  700. qdiv_exit_relay:
  701.         jmp     qdiv_exit
  702.  
  703. ; calculate (DX=0):(CX=0):BX:uqNumerator.uq0 / (SI=0):(DI=1)
  704.  
  705. div_by_one:
  706.         xchg    dx,bx                   ; DX = quotient.hi, BX = remainder.lo = 0
  707.         mov     ax,uqNumerator.uq0      ; AX = quotient.lo
  708.         jmp     qdiv_exit
  709. not_that_special:
  710.  
  711. ; handle the special case when the denominator lives in the high word
  712.  
  713.         or      di,di
  714.         jnz     not_this_special_either
  715.  
  716. ; calculate DX:CX:BX:uqNumerator.uq0 / SI:(DI=0)
  717.  
  718.         cmp     si,1                    ; separate out the trivial case
  719.         jz      div_by_10000h
  720.         mov     ax,cx
  721.         div     si
  722.         mov     cx,ax                   ; CX = quotient.hi
  723.         mov     ax,bx
  724.         div     si                      ; AX = quotient.lo
  725.         xchg    cx,dx                   ; DX = quotient.hi, CX = remainder.hi
  726.         mov     bx,uqNumerator.uq0      ; BX = remainder.lo
  727. ifdef WIMP
  728.         or      ax,ax           ; clear OF
  729. endif
  730.         jmp     qdiv_exit
  731.  
  732. ; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=1):(DI=0)
  733.  
  734. div_by_10000h:
  735.         xchg    cx,dx                   ; DX = quotient.hi, CX = remainder.hi = 0
  736.         mov     ax,bx                   ; AX = quotient.lo
  737.         mov     bx,uqNumerator.uq0      ; BX = remainder.lo
  738.         jmp     qdiv_exit
  739. not_this_special_either:
  740.  
  741. ; normalize the denominator
  742.  
  743.         mov     dx,si
  744.         mov     ax,di
  745.         call    ulNormalize             ; DX:AX = normalized denominator
  746.         mov     cShift,cx               ; CX < 16
  747.         mov     ulDenominator.lo,ax
  748.         mov     ulDenominator.hi,dx
  749.  
  750.  
  751. ; shift the Numerator by the same amount
  752.  
  753.         jcxz    numerator_is_shifted
  754.         mov     si,-1
  755.         shl     si,cl
  756.         not     si                      ; SI = mask
  757.         mov     bx,uqNumerator.uq3
  758.         shl     bx,cl
  759.         mov     ax,uqNumerator.uq2
  760.         rol     ax,cl
  761.         mov     di,si
  762.         and     di,ax
  763.         or      bx,di
  764.         mov     uqNumerator.uq3,bx
  765.         xor     ax,di
  766.         mov     bx,uqNumerator.uq1
  767.         rol     bx,cl
  768.         mov     di,si
  769.         and     di,bx
  770.         or      ax,di
  771.         mov     uqNumerator.uq2,ax
  772.         xor     bx,di
  773.         mov     ax,uqNumerator.uq0
  774.         rol     ax,cl
  775.         mov     di,si
  776.         and     di,ax
  777.         or      bx,di
  778.         mov     uqNumerator.uq1,bx
  779.         xor     ax,di
  780.         mov     uqNumerator.uq0,ax
  781. numerator_is_shifted:
  782.  
  783. ; set up registers for division
  784.  
  785.         mov     dx,uqNumerator.uq3
  786.         mov     ax,uqNumerator.uq2
  787.         mov     di,uqNumerator.uq1
  788.         mov     cx,ulDenominator.hi
  789.         mov     bx,ulDenominator.lo
  790.  
  791. ; check for case when Denominator has only 16 bits
  792.  
  793.         or      bx,bx
  794.         jnz     must_do_long_division
  795.         div     cx
  796.         mov     si,ax
  797.         mov     ax,uqNumerator.uq1
  798.         div     cx
  799.         xchg    si,dx                   ; DX:AX = quotient
  800.         mov     di,uqNumerator.uq0      ; SI:DI = remainder (shifted)
  801.         jmp     short unshift_remainder
  802. must_do_long_division:
  803.  
  804. ; do the long division, part IZ@NL@%
  805.  
  806.         cmp     dx,cx                   ; we only know that DX:AX < CX:BX!
  807.         jb      first_division_is_safe
  808.         mov     ulQuotient.hi,0         ; i.e. 10000h, our guess is too big
  809.         mov     si,ax
  810.         sub     si,bx                   ; ... remainder is negative
  811.         jmp     short first_adjuster
  812. first_division_is_safe:
  813.         div     cx
  814.         mov     ulQuotient.hi,ax
  815.         mov     si,dx
  816.         mul     bx                      ; fix remainder for low order term
  817.         sub     di,ax
  818.         sbb     si,dx
  819.         jnc     first_adjuster_done     ; The remainder is UNSIGNED!  We have
  820. first_adjuster:                         ; to use the carry flag to keep track
  821.         dec     ulQuotient.hi           ; of the sign.  The adjuster loop
  822.         add     di,bx                   ; watches for a change to the carry
  823.         adc     si,cx                   ; flag which would indicate a sign
  824.         jnc     first_adjuster          ; change IF we had more bits to keep
  825. first_adjuster_done:                    ; a sign in.
  826.  
  827. ; do the long division, part II
  828.  
  829.         mov     dx,si
  830.         mov     ax,di
  831.         mov     di,uqNumerator.uq0
  832.         cmp     dx,cx                   ; we only know that DX:AX < CX:BX!
  833.         jb      second_division_is_safe
  834.         mov     ulQuotient.lo,0         ; i.e. 10000h, our guess is too big
  835.         mov     si,ax
  836.         sub     si,bx                   ; ... remainder is negative
  837.         jmp     short second_adjuster
  838. second_division_is_safe:
  839.         div     cx
  840.         mov     ulQuotient.lo,ax
  841.         mov     si,dx
  842.         mul     bx                      ; fix remainder for low order term
  843.         sub     di,ax
  844.         sbb     si,dx
  845.         jnc     second_adjuster_done
  846. second_adjuster:
  847.         dec     ulQuotient.lo
  848.         add     di,bx
  849.         adc     si,cx
  850.         jnc     second_adjuster
  851. second_adjuster_done:
  852.         mov     ax,ulQuotient.lo
  853.         mov     dx,ulQuotient.hi
  854.  
  855. ; unshift the remainder in SI:DI
  856.  
  857. unshift_remainder:
  858.         mov     cx,cShift
  859.         jcxz    remainder_unshifted
  860.         mov     bx,-1
  861.         shr     bx,cl
  862.         not     bx
  863.         shr     di,cl
  864.         ror     si,cl
  865.         and     bx,si
  866.         or      di,bx
  867.         xor     si,bx
  868. remainder_unshifted:
  869.         mov     cx,si
  870.         mov     bx,di
  871. ifdef WIMP
  872.         or      ax,ax           ; clear OF
  873. endif
  874. qdiv_exit:
  875. cEnd
  876.  
  877. ;---------------------------Public-Routine------------------------------;
  878. ; divide
  879. ;
  880. ; Computes the FIXED quotient of two longs.  Works by noting that all
  881. ; we want is 16 bits of fraction tacked onto the quotient.  To get this,
  882. ; we multiply the numerator by 10000h, and let iqdiv do the rest.
  883. ;
  884. ; Entry:
  885. ;       DX:AX = long or FIXED numerator
  886. ;       CX:BX = long or FIXED denominator
  887. ; Returns:
  888. ;       OF = 0
  889. ;         DX:AX = FIXED quotient
  890. ; Error Returns:
  891. ;       OF = 1          ;!!! for now !!!
  892. ; Registers Destroyed:
  893. ;       BX,CX
  894. ;-----------------------------------------------------------------------;
  895.  
  896.         assumes ds,nothing
  897.         assumes es,nothing
  898.  
  899. if 0; ?386
  900.     cProc   divide,<PUBLIC,FAR,NODATA,NONWIN>
  901.         ParmD  fx1
  902.         ParmD  fx2
  903.     cBegin
  904.         mov     eax,fx1
  905.             mov     ebx,fx2         ; ebx     = denominator
  906.             xor     edx,edx
  907.             shld    edx,eax,16      ; edx:eax = numerator * 10000h
  908.             shl     eax,16
  909.             idiv    ebx
  910.             EAXtoDXAX
  911.     cEnd
  912. else
  913.     cProc   divide,<PUBLIC,FAR,NODATA,NONWIN>,<di,si>
  914.         ParmD  fx1
  915.         ParmD  fx2
  916.     cBegin
  917.         mov     ax,fx1.lo
  918.         mov     dx,fx1.hi
  919.  
  920.         mov     bx,fx2.lo
  921.         mov     cx,fx2.hi
  922.  
  923.         mov     si,cx
  924.         mov     di,bx        ; SI:DI = denominator
  925.         mov     bx,ax
  926.         mov     cx,dx
  927.         mov     ax,cx
  928.         cwd
  929.         xor     ax,ax        ; DX:CX:BX:AX = numerator * 10000h
  930.         call    iqdiv
  931.     cEnd
  932. endif
  933.  
  934. ;---------------------------Private-Macro-------------------------------;
  935. ; set_ov
  936. ;
  937. ; Sets the overflow flag
  938. ;
  939. ; Entry:
  940. ;       reg = word register to use for scratch
  941. ; Returns:
  942. ;       OF set
  943. ; Error Returns:
  944. ;       none
  945. ; Registers Destroyed:
  946. ;       reg
  947. ;-----------------------------------------------------------------------;
  948.  
  949. set_ov  macro   reg
  950.         mov     reg,8000h
  951.         dec     reg
  952.         endm
  953.  
  954. ;---------------------------Public-Routine------------------------------;
  955. ; square_root
  956. ;
  957. ; Computes the Fixed square root of a Fixed.  This algorithm
  958. ; comes from Knuth D.E; Metafont:The Program (Addison-Weseley, 1986)
  959. ; Part 8:Algebraic and Transcendental Functions.
  960. ;
  961. ; Notation used below:
  962. ;
  963. ; Entry:
  964. ;       DX:AX = number to square root
  965. ; Returns:
  966. ;         DX:AX = square root of input
  967. ; Error Returns:
  968. ;       OF = 1
  969. ; Registers Destroyed:
  970. ;       BX,CX
  971. ; Registers Preserved:
  972. ;       DS,ES,SI,DI
  973. ;-----------------------------------------------------------------------;
  974.  
  975.         assumes ds,nothing
  976.         assumes es,nothing
  977.  
  978. cProc   fxsqrt,<PUBLIC,FAR,NODATA,NONWIN>,<>
  979.         ParmD   fx
  980. cBegin
  981.     mov    ax, fx.lo
  982.         mov     dx, fx.hi
  983.  
  984.         cCall   square_root
  985.  
  986.         mov     dh,dl           ; DX:AX *= sqrt(1000h)
  987.         mov     dl,ah
  988.         mov     ah,al
  989.         xor     al,al
  990. cEnd
  991.  
  992. cProc   ulsqrt,<PUBLIC,FAR,NODATA,NONWIN>,<>
  993.         ParmD   ul
  994. cBegin
  995.         mov     ax, ul.lo
  996.         mov     dx, ul.hi
  997.  
  998.         cCall   square_root
  999. cEnd
  1000.  
  1001. ;
  1002. ;   compute the square root of EDX:EAX
  1003. ;
  1004. ;   retult returned in EAX and DX:AX
  1005. ;
  1006. ;   We dont have a 64-bit square_root function
  1007. ;   so approximate it by dividing by 4 until we can use our
  1008. ;   32-bit function
  1009. ;
  1010.  
  1011. cProc   sqrt64,<PUBLIC,NEAR,NODATA,NONWIN>,<>
  1012. cBegin
  1013.         xor     cx,cx
  1014.  
  1015. test_less_than_32:
  1016.         or      edx,edx             ; is it less than 32-bit?
  1017.         jz      less_than_32
  1018.  
  1019.         inc     cx
  1020.  
  1021.         shrd    eax,edx,2           ; divide by 4
  1022.         shr     edx,2
  1023.  
  1024.         jmp     short test_less_than_32
  1025.  
  1026. less_than_32:
  1027.         ;;
  1028.         ;;  EDX:EAX is now less than 32 bits, CX contains count of
  1029.         ;;  divisions by 4 we had to do to get here.  call square_root
  1030.         ;;  and then re-normalize
  1031.         ;;
  1032.  
  1033.         push    cx
  1034.         EAXtoDXAX
  1035.         call    square_root
  1036.         pop     cx
  1037.         jcxz    sqrt64_exit
  1038.  
  1039. @@:     shl     ax,1
  1040.         rcl     dx,1
  1041.         loop    @b
  1042.  
  1043. sqrt64_exit:
  1044.         DXAXtoEAX
  1045. cEnd
  1046.  
  1047. cProc   square_root,<PUBLIC,NEAR,NODATA,NONWIN>,<SI,DI>
  1048. ;;        ParmD   fx
  1049. cBegin
  1050. ;;        mov     ax, fx.lo
  1051. ;;        mov     dx, fx.hi
  1052. ; check for < 1 since this algorithm returns 0000:0001
  1053.  
  1054.         or      dx,dx
  1055.         jnz     non_zero_arg
  1056.         cmp     ax,1
  1057.         ja      non_zero_arg
  1058.         jmp     square_root_exit
  1059.  
  1060. negative_arg:                           ; can't have number negative
  1061.         xor     ax,ax
  1062.         cwd
  1063.         set_ov  bx
  1064.         jmp     square_root_exit
  1065.  
  1066. non_zero_arg:
  1067.         cCall   ulNormalize
  1068. ;;;;;;;;jcxz    negative_arg
  1069.         jz      exit_relay
  1070.         shr     cx,1
  1071.         jc      add_shifts_only
  1072.         shr     dx,1
  1073.         rcr     ax,1
  1074.         dec     cx
  1075. add_shifts_only:
  1076.  
  1077. ;;
  1078. ;; use 23 for a FIXED square_root, and 15 for a ULONG square_root!
  1079. ;;
  1080.  
  1081. if 0
  1082.         mov     ch,23                   ; FIXED square_root
  1083. else
  1084.         mov     ch,15                   ; ULONG square_root
  1085. endif
  1086.  
  1087.         sub     ch,cl
  1088.         mov     cl,8
  1089.         sub     ch,cl
  1090.         jg      more_than_8             ; CL = Min(count,8)
  1091.         add     cl,ch
  1092.         xor     ch,ch                   ; CH = Max(count-8,0)
  1093. more_than_8:
  1094.  
  1095.  
  1096.         xchg    ax,si                   ; DI:SI = x
  1097.         mov     di,dx
  1098.  
  1099.         xor     ax,ax                   ; AX = y = lower bound = 0
  1100.  
  1101.         mov     bx,2                    ; BX = q = estimate of root = 2
  1102.  
  1103.         add     si,si                   ; intiialize y = top bit of x
  1104.         adc     di,di
  1105.         adc     ax,ax
  1106.  
  1107. first_8_loop:
  1108.         add     si,si                   ; move 2 bits from top
  1109.         adc     di,di                   ; of x to bottom of y
  1110.         adc     ax,ax
  1111.         assert  NC
  1112.  
  1113.         add     si,si
  1114.         adc     di,di
  1115.         adc     ax,ax
  1116.         assert  NC
  1117.  
  1118.         sub     ax,bx                   ; AX = y - q
  1119.         jle     y_neg_or_zero_8
  1120.  
  1121. ;!!!CR loops can be cleaned up some
  1122.  
  1123.         add     bx,bx                   ; BX = 2q
  1124.         sub     ax,bx                   ; AX = y - 3q
  1125.         jg      y_greater_q_8
  1126.  
  1127.         add     ax,bx                   ; AX = y - q
  1128.  
  1129.         dec     cl
  1130.         jnz     first_8_loop
  1131.  
  1132.         jcxz    first_8_was_enough
  1133.         jmp     short done_with_1st_8
  1134.  
  1135. y_greater_q_8:
  1136.         add     bx,2                    ; BX = 2q + 2 (or 2q if jg not taken)
  1137.  
  1138.         dec     cl
  1139.         jnz     first_8_loop
  1140.  
  1141.         or      ch,ch
  1142.         jnz     done_with_1st_8
  1143.  
  1144. first_8_was_enough:
  1145.         xchg    ax,bx                   ; DX:AX = q
  1146.         xor     dx,dx
  1147.         shr     ax,1                    ; root = q >> 1
  1148.         or      ax,ax                   ; clear overflow flag
  1149. exit_relay:
  1150.         jmp     square_root_exit
  1151.  
  1152. y_neg_or_zero_8:                       ; come here if y <= 0
  1153.         dec     bx
  1154.         add     bx,bx                   ; BX = 2q - 2
  1155.         add     ax,bx                   ; AX = y + q - 2
  1156.  
  1157.         dec     cl
  1158.         jnz     first_8_loop
  1159.         jcxz    first_8_was_enough
  1160.  
  1161. ;si is now empty, di contains all signifigant bits
  1162. done_with_1st_8:
  1163.  
  1164.         mov     cl,4
  1165.         sub     ch,cl
  1166.         jg      second_4_loop           ; CL = Min(count,4)
  1167.         add     cl,ch
  1168.         xor     ch,ch                   ; CH = Max(count-8,0)
  1169.  
  1170. second_4_loop:
  1171.                                         ; move 2 bits from top
  1172.         add     di,di                   ; of x to bottom of y
  1173.         adc     ax,ax
  1174.         assert  NC
  1175.  
  1176.         add     di,di
  1177.         adc     ax,ax
  1178.         assert  NC
  1179.  
  1180.         sub     ax,bx                   ; AX = y - q
  1181.         jle     y_neg_or_zero_2nd_4
  1182.  
  1183.         add     bx,bx                   ; BX = 2q
  1184.  
  1185. ;!!!CR use compare and jump rather than sub, branch, and restore
  1186.         sub     ax,bx                   ; AX = y - 3q
  1187.         jg      y_greater_q_2nd_4
  1188.  
  1189.         add     ax,bx                   ; AX = y - q
  1190.  
  1191.         dec     cl
  1192.         jnz     second_4_loop
  1193.  
  1194.         jcxz    second_4_was_enough
  1195.         jmp     short done_with_2nd_4
  1196.  
  1197. y_greater_q_2nd_4:
  1198.         add     bx,2                    ; BX = 2q + 2 (or 2q if jg not taken)
  1199.  
  1200.         dec     cl
  1201.         jnz     second_4_loop
  1202.  
  1203.         or      ch,ch
  1204.         jnz     done_with_2nd_4
  1205.  
  1206.  
  1207. second_4_was_enough:
  1208.         xchg    ax,bx                   ; DX:AX = q
  1209.         xor     dx,dx
  1210.         shr     ax,1                    ; root = q >> 1
  1211.         or      ax,ax                   ; clear overflow flag
  1212.         jmp     square_root_exit
  1213.  
  1214.  
  1215. y_neg_or_zero_2nd_4:                       ; come here if y <= 0
  1216.         dec     bx
  1217.         add     bx,bx                   ; BX = 2q - 2
  1218.         add     ax,bx                   ; AX = y + q - 2
  1219.  
  1220.         dec     cl
  1221.         jnz     second_4_loop
  1222.         jcxz    second_4_was_enough
  1223.  
  1224. done_with_2nd_4:
  1225.  
  1226.         xor     dx,dx                   ; DX:AX = y   SI:BX = q
  1227.  
  1228.         mov     cl,4
  1229.         sub     ch,cl
  1230.         jg      third_4_loop             ; CL = Min(count,4)
  1231.         add     cl,ch
  1232.         xor     ch,ch                   ; CH = Max(count-13,0)
  1233.  
  1234. third_4_loop:
  1235. ;!!!CR Add comment noting that 32 bit math is being used now
  1236.                                         ; move 2 bits from top
  1237.         add     di,di                   ; of x to bottom of y
  1238.         adc     ax,ax
  1239.         adc     dx,dx
  1240.         assert  NC
  1241.  
  1242.         add     di,di
  1243.         adc     ax,ax
  1244.         adc     dx,dx
  1245.         assert  NC
  1246.  
  1247.         sub     ax,bx                   ; DX:AX = y - q
  1248.         sbb     dx,si
  1249.         js      y_negative_3rd_4
  1250.         jz      y_might_be_zero_3rd_4
  1251.  
  1252. sorry_y_not_zero_3rd_4:
  1253.         add     bx,bx
  1254.         adc     si,si                   ; SI:BX = 2q
  1255.         sub     ax,bx                   ; DX:AX = y - 3q
  1256.         sbb     dx,si
  1257.         jg      y_greater_q_3rd_4
  1258.         jl      y_less_or_equal_q_3rd_4
  1259.         or      ax,ax
  1260.         jnz     y_greater_q_3rd_4
  1261.  
  1262. y_less_or_equal_q_3rd_4:
  1263.         add     ax,bx                   ; DX:AX = y - q
  1264.         adc     dx,si
  1265.  
  1266.         dec     cl
  1267.         jnz     third_4_loop
  1268.  
  1269.         jcxz    third_4_was_enough
  1270.         jmp     short done_with_3rd_4
  1271.  
  1272. y_greater_q_3rd_4:
  1273.         add     bx,2
  1274.         adc     si,0
  1275.  
  1276.         dec     cl
  1277.         jnz     third_4_loop
  1278.  
  1279.         or      ch,ch
  1280.         jnz     done_with_3rd_4
  1281.  
  1282. third_4_was_enough:
  1283.         xchg    ax,bx                   ; DX:AX = q
  1284.         mov     dx,si
  1285.         shr     dx,1                    ; root = q >> 1
  1286.         rcr     ax,1
  1287.         or      ax,ax                   ; clear overflow flag
  1288.     jmp    square_root_exit ;;; short!
  1289.  
  1290. y_might_be_zero_3rd_4:
  1291.         or      ax,ax
  1292.         jnz     sorry_y_not_zero_3rd_4
  1293.  
  1294. y_negative_3rd_4:                       ; come here if y <= 0
  1295.  
  1296.         sub     bx,1
  1297.         sbb     si,0
  1298.         add     bx,bx                   ; DL:BX = 2q - 2
  1299.         adc     si,si
  1300.  
  1301.         add     ax,bx
  1302.         adc     dx,si                   ; DH:AX = y + q - 2
  1303.  
  1304.         dec     cl
  1305.         jnz     third_4_loop
  1306.         jcxz    third_4_was_enough
  1307.  
  1308.  
  1309. done_with_3rd_4:
  1310.  
  1311.         xchg    ch,cl
  1312.  
  1313. last_7_loop:
  1314.         add     ax,ax
  1315.         adc     dx,dx
  1316.  
  1317.         add     ax,ax
  1318.         adc     dx,dx
  1319.  
  1320.         sub     ax,bx                   ; DX:AX = y - q
  1321.         sbb     dx,si
  1322.         js      y_negative_last_7
  1323.         jz      y_might_be_zero_last_7
  1324.  
  1325. ;!!!CR Clean up the exit so that a single exit point is used.
  1326.  
  1327. sorry_y_not_zero_last_7:
  1328.         add     bx,bx
  1329.         adc     si,si                   ; SI:BX = 2q
  1330.         sub     ax,bx                   ; DX:AX = y - 3q
  1331.         sbb     dx,si
  1332.         jg      y_greater_q_last_7
  1333.         jl      y_less_or_equal_q_last_7
  1334.         or      ax,ax
  1335.         jnz     y_greater_q_last_7
  1336.  
  1337. y_less_or_equal_q_last_7:
  1338.         add     ax,bx                   ; DX:AX = y - q
  1339.         adc     dx,si
  1340.  
  1341.         loop    last_7_loop
  1342.  
  1343.         xchg    ax,bx                   ; DX:AX = q
  1344.         mov     dx,si
  1345.         shr     dx,1                    ; root = q >> 1
  1346.         rcr     ax,1
  1347.         or      ax,ax                   ; clear overflow flag
  1348.         jmp     short square_root_exit
  1349.  
  1350. y_greater_q_last_7:
  1351.         add     bx,2
  1352.         adc     si,0
  1353.  
  1354.         loop    last_7_loop
  1355.  
  1356.         xchg    ax,bx                   ; DX:AX = q
  1357.         mov     dx,si
  1358.         shr     dx,1                    ; root = q >> 1
  1359.         rcr     ax,1
  1360.         or      ax,ax                   ; clear overflow flag
  1361.         jmp     short square_root_exit
  1362.  
  1363. y_might_be_zero_last_7:
  1364.         or      ax,ax
  1365.         jnz     sorry_y_not_zero_last_7
  1366.  
  1367. y_negative_last_7:                       ; come here if y <= 0
  1368.  
  1369.         sub     bx,1
  1370.         sbb     si,0
  1371.         add     bx,bx                   ; DL:BX = 2q - 2
  1372.         adc     si,si
  1373.  
  1374.         add     ax,bx
  1375.         adc     dx,si                   ; DH:AX = y + q - 2
  1376.  
  1377.         loop    last_7_loop
  1378.  
  1379.         xchg    ax,bx                   ; DX:AX = q
  1380.         mov     dx,si
  1381.         shr     dx,1                    ; root = q >> 1
  1382.         rcr     ax,1
  1383.  
  1384.         or      ax,ax                   ; clear overflow flag
  1385. square_root_exit:
  1386. cEnd
  1387.  
  1388. ;---------------------------Public-Routine------------------------------;
  1389. ; QUAD far_big_cross_product(ptlA,ptlB)
  1390. ;
  1391. ;       See big_cross_product
  1392. ;-----------------------------------------------------------------------;
  1393.  
  1394.         assumes ds,nothing
  1395.         assumes es,nothing
  1396.  
  1397. cProc   far_big_cross_product,<PUBLIC,FAR,NONWIN,NODATA>
  1398.         parmQ   ptlA
  1399.         parmQ   ptlB
  1400. cBegin
  1401.         cCall   big_cross_product,<ptlA,ptlB>
  1402. cEnd
  1403.  
  1404. ;---------------------------Public-Routine------------------------------;
  1405. ; QUAD big_cross_product(ptlA,ptlB)
  1406. ;
  1407. ; Computes the cross product A B - A B  with total accuracy.
  1408. ;                             x y   y x
  1409. ;
  1410. ; Answer is returned in DX:CX:BX:AX.
  1411. ;
  1412. ;-----------------------------------------------------------------------;
  1413.  
  1414.         assumes ds,nothing
  1415.         assumes es,nothing
  1416.  
  1417. cProc   big_cross_product,<PUBLIC,NEAR>
  1418.         parmQ   ptlA
  1419.         parmQ   ptlB
  1420.         localQ  Result
  1421. cBegin
  1422.  
  1423. ; first do A B
  1424. ;           y x
  1425.  
  1426.         mov     ax,ptlA.ptl_y.lo
  1427.         mov     dx,ptlA.ptl_y.hi
  1428.         mov     bx,ptlB.ptl_x.lo
  1429.         mov     cx,ptlB.ptl_x.hi
  1430.         call    idmul
  1431.         mov     Result.uq0,ax
  1432.         mov     Result.uq1,bx
  1433.         mov     Result.uq2,cx
  1434.         mov     Result.uq3,dx
  1435.  
  1436. ; now do A B
  1437. ;         x y
  1438.  
  1439.         mov     ax,ptlA.ptl_x.lo
  1440.         mov     dx,ptlA.ptl_x.hi
  1441.         mov     bx,ptlB.ptl_y.lo
  1442.         mov     cx,ptlB.ptl_y.hi
  1443.         call    idmul
  1444.         sub     ax,Result.uq0
  1445.         sbb     bx,Result.uq1
  1446.         sbb     cx,Result.uq2
  1447.         sbb     dx,Result.uq3
  1448. cEnd
  1449.  
  1450. ;---------------------------Public-Routine------------------------------;
  1451. ; QUAD far_big_dot_product(ptlA,ptlB)
  1452. ;
  1453. ;       See big_dot_product
  1454. ;-----------------------------------------------------------------------;
  1455.  
  1456.         assumes ds,nothing
  1457.         assumes es,nothing
  1458.  
  1459. cProc   far_big_dot_product,<PUBLIC,FAR,NONWIN,NODATA>
  1460.         parmQ   ptlA
  1461.         parmQ   ptlB
  1462. cBegin
  1463.         cCall   big_dot_product,<ptlA,ptlB>
  1464. cEnd
  1465.  
  1466. ;---------------------------Public-Routine------------------------------;
  1467. ; QUAD big_dot_product(ptlA,ptlB)
  1468. ;
  1469. ; Computes the dot product A B + A B  with total accuracy.
  1470. ;                           x x   y y
  1471. ;
  1472. ; Answer is returned in DX:CX:BX:AX.
  1473. ;
  1474. ;-----------------------------------------------------------------------;
  1475.  
  1476.         assumes ds,nothing
  1477.         assumes es,nothing
  1478.  
  1479. cProc   big_dot_product,<PUBLIC,NEAR>
  1480.         parmQ   ptlA
  1481.         parmQ   ptlB
  1482.         localQ  Result
  1483. cBegin
  1484.  
  1485. ; first do A B
  1486. ;           x x
  1487.  
  1488.         mov     ax,ptlA.ptl_x.lo
  1489.         mov     dx,ptlA.ptl_x.hi
  1490.         mov     bx,ptlB.ptl_x.lo
  1491.         mov     cx,ptlB.ptl_x.hi
  1492.         call    idmul
  1493.         mov     Result.uq0,ax
  1494.         mov     Result.uq1,bx
  1495.         mov     Result.uq2,cx
  1496.         mov     Result.uq3,dx
  1497.  
  1498. ; now do A B
  1499. ;         y y
  1500.  
  1501.         mov     ax,ptlA.ptl_y.lo
  1502.         mov     dx,ptlA.ptl_y.hi
  1503.         mov     bx,ptlB.ptl_y.lo
  1504.         mov     cx,ptlB.ptl_y.hi
  1505.         call    idmul
  1506.         add     ax,Result.uq0
  1507.         adc     bx,Result.uq1
  1508.         adc     cx,Result.uq2
  1509.         adc     dx,Result.uq3
  1510. cEnd
  1511.  
  1512. ;---------------------------Public-Routine------------------------------;
  1513. ; ULONG lDot4D(ptA,ptB)
  1514. ;
  1515. ; Computes the dot product Ax Bx + Ay By + Az Bz  with total accuracy.
  1516. ;
  1517. ; Answer is returned in DX:AX:CX.
  1518. ;
  1519. ;-----------------------------------------------------------------------;
  1520.  
  1521.         assumes ds,nothing
  1522.         assumes es,nothing
  1523.  
  1524. cProc   lDot4D,<PUBLIC,FAR,PASCAL,NODATA,NONWIN>
  1525.         parmD   Pw
  1526.         parmD   Pz
  1527.         parmD   Py
  1528.         parmD   Px
  1529.  
  1530.         parmD   Qw
  1531.         parmD   Qz
  1532.         parmD   Qy
  1533.         parmD   Qx
  1534.  
  1535. cBegin
  1536.         xor     ebx,ebx             ; accum result in EBX:ECX
  1537.         mov     ecx,ebx
  1538.  
  1539. irp     xyz,<x,y,z>
  1540.         mov     eax,P&xyz
  1541.         imul    Q&xyz
  1542.  
  1543.         add     ecx,eax
  1544.         adc     ebx,edx
  1545. endm
  1546.         ;;
  1547.         ;;  return result in DX:AX:CX
  1548.         ;;
  1549.         shr     ecx,16
  1550.         mov     eax,ebx
  1551.         EAXtoDXAX
  1552. cEnd
  1553.  
  1554. ;---------------------------Public-Routine------------------------------;
  1555. ; fxCross4D(pvV,vP,vQ)
  1556. ;
  1557. ; Computes the cross product of vector vP and vector vQ
  1558. ;
  1559. ; result is stored in *pvV
  1560. ;
  1561. ;    v.x =   P.y*Q.z - P.z*Q.y
  1562. ;    v.y =  -P.x*Q.z - P.z*Q.x
  1563. ;    v.z =   P.x*Q.y - P.y*Q.x
  1564. ;
  1565. ;-----------------------------------------------------------------------;
  1566.  
  1567.         assumes ds,nothing
  1568.         assumes es,nothing
  1569.  
  1570. cProc   fxCross4D,<PUBLIC,FAR,PASCAL,NODATA,NONWIN>
  1571.         parmD   ppR
  1572.  
  1573.         parmD   Pw
  1574.         parmD   Pz
  1575.         parmD   Py
  1576.         parmD   Px
  1577.  
  1578.         parmD   Qw
  1579.         parmD   Qz
  1580.         parmD   Qy
  1581.         parmD   Qx
  1582.  
  1583. cBegin
  1584.         les     di,ppR
  1585. ;
  1586. ;    v.x =   P.y*Q.z - P.z*Q.y
  1587. ;
  1588.         mov     eax,Py
  1589.         mov     edx,Qz
  1590.         imul    edx
  1591.         mov     ebx,edx
  1592.         mov     ecx,eax
  1593.         mov     eax,Pz
  1594.         mov     edx,Qy
  1595.         imul    edx
  1596.         sub     ecx,eax
  1597.         sbb     ebx,edx
  1598.  
  1599.         shrd    ecx,ebx,16
  1600.         mov     es:[di].x,ecx
  1601. ;
  1602. ;    v.y =  -P.x*Q.z - P.z*Q.x
  1603. ;
  1604.         mov     eax,Px
  1605.         mov     edx,Qz
  1606.         neg     eax
  1607.         imul    edx
  1608.         mov     ebx,edx
  1609.         mov     ecx,eax
  1610.         mov     eax,Pz
  1611.         mov     edx,Qx
  1612.         imul    edx
  1613.         sub     ecx,eax
  1614.         sbb     ebx,edx
  1615.  
  1616.         shrd    ecx,ebx,16
  1617.         mov     es:[di].y,ecx
  1618. ;
  1619. ;    v.z =   P.x*Q.y - P.y*Q.x
  1620. ;
  1621.         mov     eax,Px
  1622.         mov     edx,Qy
  1623.         imul    edx
  1624.         mov     ebx,edx
  1625.         mov     ecx,eax
  1626.         mov     eax,Py
  1627.         mov     edx,Qx
  1628.         imul    edx
  1629.         sub     ecx,eax
  1630.         sbb     ebx,edx
  1631.  
  1632.         shrd    ecx,ebx,16
  1633.         mov     es:[di].z,ecx
  1634.  
  1635.         xor     eax,eax
  1636.         mov     es:[di].w,eax
  1637. cEnd
  1638.  
  1639. ;---------------------------Public-Routine------------------------------;
  1640. ; FIXED fxLength3D(Vx,Vy,Vz)
  1641. ;
  1642. ; Computes length of the vector V as a FIXED number
  1643. ;
  1644. ; Answer is returned in DX:AX:CX.
  1645. ;
  1646. ;-----------------------------------------------------------------------;
  1647.  
  1648.         assumes ds,nothing
  1649.         assumes es,nothing
  1650.  
  1651. cProc   fxLength3D,<PUBLIC,FAR,PASCAL,NODATA,NONWIN>
  1652.         parmD   Vx
  1653.         parmD   Vy
  1654.         parmD   Vz
  1655. cBegin
  1656.         xor     ebx,ebx             ; accum sum of squares in EBX:ECX
  1657.         mov     ecx,ebx
  1658.  
  1659. irp     xyz,<x,y,z>
  1660.         mov     eax,V&xyz           ; EAX = Vi
  1661.         imul    eax                 ; EDX:EAX = Vi^2
  1662.  
  1663.         add     ecx,eax             ; EBX:ECX += Vi^2
  1664.         adc     ebx,edx
  1665. endm
  1666.         mov     eax,ecx
  1667.         mov     edx,ebx
  1668.         ;;
  1669.         ;;  EDX:EAX now contains sum of squares*1000h, take the square_root
  1670.  
  1671.         cCall   sqrt64              ; calculates sqrt(EDX:EAX) ==> DX:AX
  1672. cEnd
  1673.  
  1674. sEnd    MathSeg
  1675.  
  1676. .286
  1677.  
  1678. if ?386
  1679.     .386
  1680. endif
  1681.  
  1682. sBegin TrigSeg
  1683.     assumes cs,TrigSeg
  1684.  
  1685.     include vttable.inc
  1686.  
  1687. ;----------------------------Public-Routine-----------------------------;
  1688. ; CalcSine
  1689. ;
  1690. ; Computes sine(angle).
  1691. ;
  1692. ; Entry:
  1693. ;       DX:AX = angle UNSIGNED FIXED
  1694. ;
  1695. ; Returns:
  1696. ;       BX = 1 => OK.
  1697. ;       DX:AX = result.
  1698. ;
  1699. ; Error Returns:
  1700. ;       BX = 0.
  1701. ;
  1702. ; Registers Destroyed:
  1703. ;       CX, flags.
  1704. ;
  1705. ;-----------------------------------------------------------------------;
  1706.  
  1707.         assumes ds,nothing
  1708.         assumes es,nothing
  1709.         
  1710. cProc    CalcSine,<FAR,PUBLIC>
  1711.     ParmD    fx
  1712. cBegin
  1713.     mov    ax,fx.lo
  1714.     mov    dx,fx.hi
  1715.  
  1716.         sub     dx,90
  1717.         jnc     no_wrap
  1718.         add     dx,360
  1719. no_wrap:
  1720.     push    dx
  1721.     push    ax
  1722. ;;;       errn$   CalcCosine
  1723.     call    FAR PTR CalcCosine
  1724. cEnd
  1725.  
  1726. ;----------------------------Public-Routine-----------------------------;
  1727. ; CalcCosine
  1728. ;
  1729. ; Computes Cosine(angle).
  1730. ;
  1731. ; Entry:
  1732. ;       DX:AX = angle UNSIGNED FIXED
  1733. ;
  1734. ; Returns:
  1735. ;       BX = 1 => OK.
  1736. ;       DX:AX = result.
  1737. ;
  1738. ; Error Returns:
  1739. ;       BX = 0.
  1740. ;
  1741. ; Registers Destroyed:
  1742. ;       CX, flags.
  1743. ;
  1744. ;-----------------------------------------------------------------------;
  1745.  
  1746. ;----------------------------Pseudo-Code--------------------------------;
  1747. ; INTEGER FAR PASCAL CalcCosine(FIXED)
  1748. ; short R;
  1749. ; short Angle;
  1750. ; {
  1751. ;   negateflag = 0;         // don't want result negated 
  1752. ;
  1753. ;   AX = Angle;
  1754. ;   AX -= 900;
  1755. ;
  1756. ;   if (Angle <= 900)
  1757. ;   {
  1758. ;       jump to negate_cos_result;     // return RTable(R, 900 - Angle) 
  1759. ;   }
  1760. ;
  1761. ;   negateflag = -1;        // want result negated 
  1762. ;
  1763. ;   if (Angle <= 1800)
  1764. ;   {
  1765. ;       jump to no_cos_negation;     // return -RTable(R, Angle - 900) 
  1766. ;   }
  1767. ;
  1768. ;   AX -= 1800;
  1769. ;
  1770. ;   if (Angle <= 2700)
  1771. ;   {
  1772. ;       jump to negate_cos_result;     // return -RTable(R, 2700 - Angle) 
  1773. ;   }
  1774. ;
  1775. ;   negateflag = 0;         // dont want result negated 
  1776. ;
  1777. ;   jump to no_cos_negation;        // return RTable(R, Angle - 2700) 
  1778. ;
  1779. ;negate_cos_result:
  1780. ;   negate AX;
  1781. ;
  1782. ;no_cos_negation:
  1783. ;   jump to RTable;
  1784. ; }
  1785. ;-----------------------------------------------------------------------;
  1786.  
  1787.         assumes ds,nothing
  1788.         assumes es,nothing
  1789.  
  1790. cProc    CalcCosine,<FAR,PUBLIC>
  1791.     ParmD    fx
  1792. cBegin
  1793.     mov    ax,fx.lo
  1794.     mov    dx,fx.hi
  1795.  
  1796.         xor     cx,cx                   ;Don't want result negated
  1797.         sub     dx,90                   ; if angle <= 90
  1798.         jg      greater_than_90
  1799.         jl      negate_cos_result       ;  return r_table(R,90 - angle)
  1800.         or      ax,ax
  1801.         jz      negate_cos_result
  1802. greater_than_90:
  1803.  
  1804.         dec     cx                      ;Want result negated
  1805.         mov     bx,dx                   ;If Angle <= 180
  1806.         sub     bx,90                   ;  return -RTable(R,Angle-90)
  1807.         jg      greater_than_180
  1808.         jl      no_cos_negation
  1809.         or      ax,ax
  1810.         jz      no_cos_negation
  1811. greater_than_180:
  1812.  
  1813.         sub     dx,180                  ;If Angle < 270
  1814.         jl      negate_cos_result       ;  return -RTable(R,270-Angle)
  1815.  
  1816.         inc     cx                      ;Don't want result negated
  1817.         jmp     short no_cos_negation   ;  return RTable(R,Angle-270)
  1818.  
  1819. negate_cos_result:
  1820.         neg     ax                      ; do the negation.
  1821.         adc     dx,0
  1822.         neg     dx
  1823.  
  1824. no_cos_negation:
  1825.         push    cx                      ; Save negation flag
  1826.  
  1827.     push    di            ; Interpolation
  1828.     mov    di,dx
  1829.  
  1830.     imul    di,10
  1831.  
  1832.     shl    di,1            ; make it a word index.
  1833.     mov    dx,cs:vttable[di][0]    ; Get base value
  1834. if 0
  1835.         push    dx                      ; save base value.
  1836.     mov    cx,cs:vttable[di][2]    ; find (difference between adjacent
  1837.         sub     cx,dx
  1838.         xor     dx,dx
  1839.     xor    bx,bx
  1840.  
  1841.     push    dx
  1842.     push    ax
  1843.     push    cx
  1844.     push    bx
  1845.     call    multiply        ; call    far_multiply
  1846.  
  1847.         pop     ax
  1848.         add     dx,ax
  1849. endif
  1850.         xor     ax,ax
  1851.         mov     cx,10000
  1852.         xor     bx,bx
  1853.  
  1854.     push    dx
  1855.     push    ax
  1856.     push    cx
  1857.     push    bx
  1858.         call    divide
  1859.  
  1860.         pop     di
  1861.         pop     cx                      ; Negate result if needed
  1862.         jcxz    r_table_exit
  1863.  
  1864.         neg     ax                      ; do the negation.
  1865.         adc     dx,0
  1866.         neg     dx
  1867. r_table_exit:
  1868.  
  1869. cEnd
  1870.  
  1871. sEnd TrigSeg
  1872.  
  1873.        end
  1874.